package com.bening.smsapp.parser;

import com.bening.smsapp.bean.*;

import com.bening.smsapp.factory.SmsAppFactory;
import com.bening.smsapp.util.SmsAppTools;

import org.apache.commons.beanutils.*;
import com.bening.smsapp.bootstrap.BootConfigParameters;
import com.bening.smsapp.constant.PropertiesConstant;
import com.bening.smsapp.constant.SmsAppConstant;
import com.bening.smsapp.dao.*;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;

import org.apache.log4j.Logger;

public class AsciiParser 
{

	private static BootConfigParameters bootParam = BootConfigParameters.getInstance();
	final static Logger logger = Logger.getLogger( AsciiParser.class );
	private static SmsAppDao smsDao = SmsAppFactory.getDaoObject();
	private static int myLine = 0;
	
    public AsciiParser() {
		// TODO Auto-generated constructor stub
	}

    /**
     * parse a single file, given the folder name and filename.
     * @param folder
     * @param filename
     */
    public static void parseFileToDatabase( String folder, String filename , int sourcePathId)
    {
        Logger logger = Logger.getLogger( AsciiParser.class );
        final String METHOD_SIGNATURE = "[parser]";
        List fileContent = new ArrayList();
        List parseResult = new ArrayList();
        
        int lineError = 0;
        int lineNum = 0;
        
        BufferedReader reader;
        // update start processing time
        try  {
        	SmsAppTools.updateFileStatus(filename, SmsAppConstant.FLAG_PARSE_RUNNING);
        }catch(SQLException s) {
        	logger.error(s);
        	SmsAppTools.InsertEventLog(SmsAppConstant.SQL_ERROR, s.getMessage(), sourcePathId);
        }

        try
        {
            if ( logger.isInfoEnabled() )
            {
                logger.info( METHOD_SIGNATURE + "parsing file: " + filename );
            }

            reader = new BufferedReader( new FileReader( folder + File.separator + filename ) );
            String currentLine = reader.readLine();
            
            while( currentLine != null )
            {
                fileContent.add(lineNum,currentLine);
                lineNum++;
                currentLine = reader.readLine();
            }
            reader.close();
            
            // parsing start
            for(int i=0;i<fileContent.size();i++) {
            	parseResult.add(i,ParseToBean((String)fileContent.get(i)));
            }
            // parsing end
            // insert result to database
            try {
            	smsDao.insertParsingResultAscii(parseResult,filename);
            }catch(SQLException s) {
            	lineError++;
            	SmsAppTools.InsertEventLog(SmsAppConstant.SQL_ERROR, s.getMessage()+"-"+filename, sourcePathId);
            }
            
            if ( logger.isInfoEnabled() )
            {
                logger.info( METHOD_SIGNATURE + "file: " + filename + "Total lines processed: " + lineNum );            }
        }
        catch ( IOException e )
        {
            logger.error( METHOD_SIGNATURE + e.getClass() + ": " + e.getMessage(), e );
        }

        if ( logger.isInfoEnabled() )
        {
            logger.info( METHOD_SIGNATURE + "updating process status to database." );
        }
        // update end processing time
        try  {
        	SmsAppTools.updateFileStatus(filename, SmsAppConstant.FLAG_PARSE_DONE);
        }catch(SQLException s) {
        	logger.error(s);
        	SmsAppTools.InsertEventLog(SmsAppConstant.SQL_ERROR, s.getMessage(), sourcePathId);
        }
        
    }
    
    private static FixedLengthAsciiBean ParseToBean(String oneLine) {
     	if("".equals(oneLine) || oneLine == null) return null;
    	
    	List rule = bootParam.getAsciiParserRule();
    	
    	FixedLengthAsciiBean f = new FixedLengthAsciiBean();
    	int beginIndex=0;
    	int endIndex=0;
    	
    	
    	for(int j=0;j<rule.size();j++) {

	    		FieldValueRuleBean fvb = (FieldValueRuleBean)rule.get(j);
	    		endIndex = endIndex + fvb.getValueRule();
	    		int len = endIndex;
	    		if(len<=oneLine.length()) {
	    			
	    		Object content = oneLine.substring(beginIndex, endIndex); 
	    		try {
	    			// convert to date first if found date
	    			if(fvb.getNameRule().equals("msgSubTime")) {
	    				content = toDateString((String)content);
	    			}
	    			else if(fvb.getNameRule().equals("msgDlrTime")) {
	    				content = toDateString((String)content);
	    			}
	    			
	    			BeanUtils.setProperty(f, fvb.getNameRule(),content );
	    		}catch(InvocationTargetException ite) {
	    			logger.error("Error in InvocationTargetException",ite);
	    		}catch(IllegalAccessException ile) {
	    			logger.error("Error in IllegalAccessException",ile);
	    		}
	    		beginIndex = endIndex;
    		}
    	}    	
    	//System.out.println(myLine++);
    	return normalizeAndFlagging(f);
    }
    
    
    private static FixedLengthAsciiBean normalizeAndFlagging(FixedLengthAsciiBean input) {
    	FixedLengthAsciiBean result = input;
    	// trim  clgNumber
    	input.setClgNumber(normalizePrefix(trimZeroPrefix(input.getClgNumber())));
    	input.setCldNumber(normalizePrefix(trimZeroPrefix(input.getCldNumber())));
    	input.setClgFlag(flagging(input.getClgNumber()));
    	input.setCldFlag(flagging(input.getCldNumber()));
    	
    	input.setCldCustId(trimZeroPrefix(input.getCldCustId()));
    	input.setClgCustId(trimZeroPrefix(input.getClgCustId()));
    	
    	input.setClgMscGt(trimZeroPrefix(input.getClgMscGt()));
    	input.setCldMscGt(trimZeroPrefix(input.getCldMscGt()));
    	input.setClgImsi(trimZeroPrefix(input.getClgImsi()));
    	input.setCldImsi(trimZeroPrefix(input.getCldImsi()));
//    	input.setMsgLength(Long.valueOf(trimZeroPrefix(String.valueOf(input.getMsgLength()))).longValue());
//    	input.setNbAttempt(Long.valueOf(trimZeroPrefix(String.valueOf(input.getNbAttempt()))).longValue());
//    	
    	input.setMsgState(trimSpaces(String.valueOf(input.getMsgState())));
//    	input.setMsgStatus(Long.valueOf(trimSpaces(String.valueOf(input.getMsgStatus()))).longValue());
//    	
    	return result;
    }
    private static String trimZeroPrefix(String input) {
    	if(input==null ) return "0";
    	else if("".equals(input.trim())) return "0";
    	else if("0".equals(input)) return "0";
    	else 
    	return input.replaceAll("^0*", "");
    }
    private static String trimSpaces(String input) {
    	if(input==null ) return "";
    	else 
    	return input.replaceAll("^\\s*", "");
    }
    private static Date toDateString(String date) {
    	String dateStr = date.substring(0,date.length()-4);
    	SimpleDateFormat sdf = new SimpleDateFormat("yyMMddhhmmss");
    	try {
    		return sdf.parse(dateStr);
    	}catch(ParseException p) {
    		return null;
    	}
    }
    private static String flagging(String input) {
    	String result = "";
    	if(input==null||"".equals(input)) return "";
    	int len = input.length();
    	if(len<=6) {
    		result = SmsAppConstant.FLAG_MACHINE;
    	}else {
    		String prefix = input.substring(0,5);
    		result = bootParam.getFlaggingRuleProperties().getProperty(prefix);
    		if(result == null) {
    			result = SmsAppConstant.FLAG_EXT_OPERS;
    		}
    	}
    	return result;
    }
    private static String normalizePrefix(String input) {
    	String result = "";
    	if(input==null||"".equals(input)) return "";
    	else if(input.length()<4) return "";
    	
    	if(!input.substring(0,2).equals("62")) {
    		if(input.length()<=6) {
    			result = input;
    		}
    		else {
    			String temp = "62"+input.substring(0,3);
    			if(bootParam.getFlaggingRuleProperties().getProperty(temp)!=null) {
    				result = "62"+input;
    			}
    			else {
    				result = input;
    			}
    		}
    	}
    	else {
    		result = input;
    	}
    	
    	return result;
    }
}
